package monitor

import (
	"log"
	"os"
	"path/filepath"
	"sftp-monitor/internal/sftpClient"
	"time"
)

type DownloadFile struct {
	Name string
	Size int64
}

func RemoteWatcher(remoteDir, localDir, Username, Password, Host string, Port int, TimeInterval time.Duration, SupportCatalogs, WhetherDelete bool) {
	SftpClient := sftpClient.SFTP{}
	err := SftpClient.Connect(Username, Password, Host, Port)
	defer SftpClient.Close()
	if err != nil {
		log.Fatalf("SftpClient.Connect err: %v", err)
	}
	downloadedFiles := make(map[string]DownloadFile)
	log.Println("SftpClient.Connect start")
	log.Printf("本地监听目录：%s；开始检查远程目录：%s", localDir, remoteDir)
	for {
		//log.Printf("downloadedFiles:%v", downloadedFiles)
		//Client := sftpClient.SFTP{}
		// 列出远程目录中的文件
		files, err := SftpClient.ReadDir(remoteDir)
		if err != nil {
			log.Printf("读取远程目录时出错: %v", err)
			time.Sleep(5 * time.Second)
			continue
		}

		for _, file := range files {
			remotePath := filepath.Join(remoteDir, file.Name())
			localPath := filepath.Join(localDir, file.Name())
			if !file.IsDir() {
				downloadedFiles, err = remoteFileDownload(downloadedFiles, file, SftpClient, remotePath, localPath)
				if err != nil {
					log.Printf("remoteFileDownload err: %v", err)
				} else {
					if WhetherDelete {
						remotePath = filepath.ToSlash(remotePath)
						err := SftpClient.DeleteRemoteFile(remotePath)
						if err != nil {
							log.Printf("SftpClient.DeleteRemoteFile err: %s|%v", remotePath, err)
							//return
						} else {
							log.Printf("SftpClient.DeleteRemoteFile success:%s", remotePath)
						}
					}
				}
			} else {
				if SupportCatalogs {
					downloadedFiles = remoteDirectory(downloadedFiles, file, SftpClient, remotePath, localPath)
					if err != nil {
						log.Printf("remoteFileDownload err: %v", err)
					} else {
						if WhetherDelete {
							remotePath = filepath.ToSlash(remotePath)
							err := SftpClient.DeleteRemoteFile(remotePath)
							if err != nil {
								log.Printf("SftpClient.DeleteRemoteFile err: %s|%v", remotePath, err)
								//return
							}
						}
					}
				}
			}
		}
		//log.Printf("%v\n", TimeInterval)
		newFiles, err := getRemoteFiles(SftpClient, remoteDir, SupportCatalogs)
		if err != nil {
			log.Printf("getNewRemoteFiles err: %v", err)
		}
		downloadedFiles = newFiles
		newFiles = nil
		// 检查间隔
		time.Sleep(TimeInterval)
	}
}

func remoteFileDownload(downloadedFiles map[string]DownloadFile, file os.FileInfo, SftpClient sftpClient.SFTP, remotePath, localPath string) (map[string]DownloadFile, error) {
	// 检查文件是否已下载或文件大小是否有变化
	if downloaded, exists := downloadedFiles[file.Name()]; !exists || downloaded.Size != file.Size() {
		// 下载新文件或文件大小有变化的文件
		err := SftpClient.Download(remotePath, localPath)
		if err != nil {
			log.Printf("下载文件 %s 时出错: %v", remotePath, err)
			return downloadedFiles, err
		} else {
			log.Printf("成功下载文件: %s", remotePath)
			// 更新已下载文件的信息
			downloadedFiles[file.Name()] = DownloadFile{
				Name: file.Name(),
				Size: file.Size(),
			}
		}
	}
	return downloadedFiles, nil
}

func remoteDirectory(downloadedFiles map[string]DownloadFile, file os.FileInfo, SftpClient sftpClient.SFTP, remotePath, localPath string) map[string]DownloadFile {
	if downloaded, exists := downloadedFiles[file.Name()]; !exists || downloaded.Size != file.Size() {
		err := SftpClient.DownloadRemoteDirectory(remotePath, localPath)
		if err != nil {
			log.Printf("下载目录 %s 时出错: %v", remotePath, err)
		} else {
			log.Printf("成功下载目录: %s", remotePath)
			// 更新已下载文件的信息
			downloadedFiles[file.Name()] = DownloadFile{
				Name: file.Name(),
				Size: file.Size(),
			}
		}
	}
	return downloadedFiles
}

// 获取指定目录下的文件和子目录信息
func getRemoteFiles(SftpClient sftpClient.SFTP, remoteDir string, SupportCatalogs bool) (map[string]DownloadFile, error) {
	files := make(map[string]DownloadFile)
	entries, err := SftpClient.ReadDir(remoteDir)
	if err != nil {
		return nil, err
	}
	for _, file := range entries {
		if file.IsDir() {
			if SupportCatalogs {
				files[file.Name()] = DownloadFile{
					Name: file.Name(),
					Size: file.Size(),
				}
			}
		} else {
			files[file.Name()] = DownloadFile{
				Name: file.Name(),
				Size: file.Size(),
			}
		}
	}
	return files, nil
}
